package com.platform.core.service.impl;

import com.google.common.base.Strings;
import com.platform.core.repository.SysDictItemRepository;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Predicate;
import com.platform.comm.dto.DtoMapper;
import com.platform.comm.enums.YnEnum;
import com.platform.dto.DictItemQo;
import com.platform.core.entity.QSysDictGroup;
import com.platform.core.entity.QSysDictItem;
import com.platform.core.entity.SysDictItem;
import com.platform.core.service.SysDictItemService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.QSort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import static com.platform.comm.constants.GlobalConstant.BASE_REDIS_CACHE_PREFIX;

/**
 * Description: 字典项-Service实现类
 *
 * @author libin Created on 2019/7/17
 **/
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class SysDictItemServiceImpl extends BaseEntityBizImpl<SysDictItemRepository, SysDictItem> implements SysDictItemService {

    private final QSysDictItem qSysDictItem = QSysDictItem.sysDictItem;
    private final QSysDictGroup qSysDictGroup = QSysDictGroup.sysDictGroup;
    private final DtoMapper dtoMapper;
    private final SysDictItemRepository sysDictItemRepository;

    public SysDictItemServiceImpl(SysDictItemRepository sysDictItemRepository, DtoMapper dtoMapper) {
        super(sysDictItemRepository);
        this.sysDictItemRepository = sysDictItemRepository;
        this.dtoMapper = dtoMapper;
    }

    @Override
    public Page<DictItemQo> queryItems(Predicate predicate, Pageable pageable, MultiValueMap<String, String> parameters) {
        if (pageable.getSort().isUnsorted()) {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), QSort.by(qSysDictItem.sortNum.asc()));
        }
        BooleanBuilder bool = new BooleanBuilder(predicate);
        String itemName = parameters.getFirst("itemName");
        if (StringUtils.isNoneBlank(itemName)) {
            bool.and(qSysDictItem.itemName.contains(itemName));
        }
        String itemCode = parameters.getFirst("itemCode");
        if (StringUtils.isNoneBlank(itemCode)) {
            bool.and(qSysDictItem.itemCode.contains(itemCode));
        }
        bool.and(qSysDictItem.groupId.eq(parameters.getFirst("groupId")));
        Page<SysDictItem> page = queryByPage(builderConditions(bool, parameters, SysDictItem.class, qSysDictItem.getMetadata()), pageable);
        return page.map(entity -> dtoMapper.map(entity, DictItemQo.class));
    }

    @CacheEvict(value = BASE_REDIS_CACHE_PREFIX + "dict", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public DictItemQo create(DictItemQo dictItemQo) {
        dictItemQo.init();
        SysDictItem entity = dtoMapper.map(dictItemQo, SysDictItem.class);
        saveEntity(entity);
        return dtoMapper.map(entity, DictItemQo.class);
    }

    @CacheEvict(value = BASE_REDIS_CACHE_PREFIX + "dict", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public DictItemQo modify(DictItemQo dictItemQo) {
        SysDictItem entity = fetchById(dictItemQo.getId());
        dtoMapper.map(dictItemQo, entity);
        entity.setUpdateDate(LocalDateTime.now());
        saveEntity(entity);
        return dtoMapper.map(entity, DictItemQo.class);
    }

    @CacheEvict(value = BASE_REDIS_CACHE_PREFIX + "dict", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void remove(String id) {
        repository.deleteById(id);
    }

    @Override
    public Long validDictItemCode(String id, String groupId, String itemCode) {
        BooleanBuilder builder = buildValidConditions(id, groupId);
        builder.and(qSysDictItem.itemCode.eq(itemCode));
        return repository.count(builder);
    }

    @Override
    public Long validDictItemName(String id, String groupId, String itemName) {
        BooleanBuilder builder = buildValidConditions(id, groupId);
        builder.and(qSysDictItem.itemName.eq(itemName));
        return repository.count(builder);
    }

    @Override
    public List<DictItemQo> queryItemsByGroupCode(String groupCode) {
        List<Tuple> tupleList = this.sysDictItemRepository.findAll(jpqlQuery -> jpqlQuery.from(qSysDictItem)
                .leftJoin(qSysDictGroup).on(qSysDictItem.groupId.eq(qSysDictGroup.id))
                .where(qSysDictGroup.groupCode.eq(groupCode).and(qSysDictItem.delFlag.eq(YnEnum.N)))
                .orderBy(qSysDictItem.sortNum.asc()), qSysDictItem.itemCode, qSysDictItem.itemName);
        return tupleList.stream()
                .map(tuple -> {
                    DictItemQo dictItemQo = new DictItemQo();
                    dictItemQo.setItemCode(tuple.get(qSysDictItem.itemCode));
                    dictItemQo.setItemName(tuple.get(qSysDictItem.itemName));
                    return dictItemQo;
                }).collect(Collectors.toList());
    }

    private BooleanBuilder buildValidConditions(String id, String groupId) {
        BooleanBuilder builder = new BooleanBuilder(qSysDictItem.groupId.eq(groupId));
        if (!Strings.isNullOrEmpty(id)) {
            builder.and(qSysDictItem.id.ne(id));
        }
        return builder;
    }
}
